#!/usr/bin/env python3
"""
主机监控模块 - 用于在Docker容器中监控物理主机资源
"""

import os
import psutil
from typing import Dict, Optional
import logging

logger = logging.getLogger(__name__)

class HostMonitor:
    """主机监控器 - 在容器中监控物理主机资源"""
    
    def __init__(self, host_proc_path: str = "/host/proc", host_sys_path: str = "/host/sys"):
        """
        初始化主机监控器
        
        Args:
            host_proc_path: 主机/proc文件系统挂载点
            host_sys_path: 主机/sys文件系统挂载点
        """
        self.host_proc_path = host_proc_path
        self.host_sys_path = host_sys_path
        self.is_in_container = self._detect_container_environment()
        
        if self.is_in_container:
            logger.info(f"检测到容器环境，将使用主机挂载点监控: {host_proc_path}")
        else:
            logger.info("检测到本地环境，将直接监控本机资源")
    
    def _detect_container_environment(self) -> bool:
        """检测是否在容器环境中运行"""
        # 检查是否存在主机挂载点
        if os.path.exists(self.host_proc_path) and os.path.exists(f"{self.host_proc_path}/version"):
            return True
        
        # 检查容器环境标识
        if os.path.exists("/.dockerenv"):
            return True
            
        # 检查cgroup信息
        try:
            with open("/proc/1/cgroup", "r") as f:
                content = f.read()
                if "docker" in content or "containerd" in content:
                    return True
        except:
            pass
            
        return False
    
    def get_host_cpu_info(self) -> Dict:
        """获取主机CPU信息"""
        if self.is_in_container:
            return self._get_host_cpu_from_proc()
        else:
            return self._get_local_cpu_info()
    
    def _get_host_cpu_from_proc(self) -> Dict:
        """从/host/proc读取主机CPU信息"""
        try:
            # 读取CPU统计信息
            stat_file = f"{self.host_proc_path}/stat"
            with open(stat_file, 'r') as f:
                cpu_line = f.readline().strip()
            
            # 解析CPU时间
            cpu_times = list(map(int, cpu_line.split()[1:8]))
            total_time = sum(cpu_times)
            idle_time = cpu_times[3]  # idle time
            
            # 计算CPU使用率（需要两次采样）
            import time
            time.sleep(0.1)
            
            with open(stat_file, 'r') as f:
                cpu_line2 = f.readline().strip()
            cpu_times2 = list(map(int, cpu_line2.split()[1:8]))
            total_time2 = sum(cpu_times2)
            idle_time2 = cpu_times2[3]
            
            total_diff = total_time2 - total_time
            idle_diff = idle_time2 - idle_time
            
            if total_diff > 0:
                cpu_percent = 100.0 * (total_diff - idle_diff) / total_diff
            else:
                cpu_percent = 0.0
            
            # 读取CPU核心数
            cpuinfo_file = f"{self.host_proc_path}/cpuinfo"
            cpu_count = 0
            with open(cpuinfo_file, 'r') as f:
                for line in f:
                    if line.startswith('processor'):
                        cpu_count += 1
            
            return {
                'percent': round(cpu_percent, 1),
                'count': cpu_count,
                'load_avg': self._get_host_load_avg()
            }
            
        except Exception as e:
            logger.error(f"读取主机CPU信息失败: {e}")
            return self._get_local_cpu_info()
    
    def _get_local_cpu_info(self) -> Dict:
        """获取本地CPU信息"""
        return {
            'percent': psutil.cpu_percent(interval=1),
            'count': psutil.cpu_count(),
            'load_avg': list(os.getloadavg()) if hasattr(os, 'getloadavg') else [0, 0, 0]
        }
    
    def _get_host_load_avg(self) -> list:
        """获取主机负载平均值"""
        try:
            loadavg_file = f"{self.host_proc_path}/loadavg"
            with open(loadavg_file, 'r') as f:
                load_data = f.read().strip().split()
                return [float(load_data[0]), float(load_data[1]), float(load_data[2])]
        except:
            return [0, 0, 0]
    
    def get_host_memory_info(self) -> Dict:
        """获取主机内存信息"""
        if self.is_in_container:
            return self._get_host_memory_from_proc()
        else:
            return self._get_local_memory_info()
    
    def _get_host_memory_from_proc(self) -> Dict:
        """从/host/proc读取主机内存信息"""
        try:
            meminfo_file = f"{self.host_proc_path}/meminfo"
            memory_info = {}
            
            with open(meminfo_file, 'r') as f:
                for line in f:
                    if ':' in line:
                        key, value = line.split(':', 1)
                        # 提取数值（KB）
                        value_kb = int(value.strip().split()[0])
                        memory_info[key.strip()] = value_kb * 1024  # 转换为字节
            
            total = memory_info.get('MemTotal', 0)
            available = memory_info.get('MemAvailable', 0)
            free = memory_info.get('MemFree', 0)
            buffers = memory_info.get('Buffers', 0)
            cached = memory_info.get('Cached', 0)
            
            # 如果没有MemAvailable，使用估算值
            if available == 0:
                available = free + buffers + cached
            
            used = total - available
            percent = (used / total * 100) if total > 0 else 0
            
            return {
                'total': total,
                'available': available,
                'used': used,
                'free': free,
                'percent': round(percent, 1),
                'buffers': buffers,
                'cached': cached
            }
            
        except Exception as e:
            logger.error(f"读取主机内存信息失败: {e}")
            return self._get_local_memory_info()
    
    def _get_local_memory_info(self) -> Dict:
        """获取本地内存信息"""
        memory = psutil.virtual_memory()
        return {
            'total': memory.total,
            'available': memory.available,
            'used': memory.used,
            'free': memory.free,
            'percent': memory.percent,
            'buffers': getattr(memory, 'buffers', 0),
            'cached': getattr(memory, 'cached', 0)
        }
    
    def get_host_disk_info(self) -> Dict:
        """获取主机磁盘信息"""
        if self.is_in_container:
            # 在容器中，仍然可以通过挂载的根文件系统获取磁盘信息
            # 但需要注意路径映射
            return self._get_disk_info_from_mounts()
        else:
            return self._get_local_disk_info()
    
    def _get_disk_info_from_mounts(self) -> Dict:
        """从挂载点获取磁盘信息"""
        disk_usage = {}
        
        # 如果挂载了主机根目录
        host_root = "/host/root"
        if os.path.exists(host_root):
            try:
                # 获取主机根分区使用情况
                usage = psutil.disk_usage(host_root)
                disk_usage["/"] = {
                    'total': usage.total,
                    'used': usage.used,
                    'free': usage.free,
                    'percent': (usage.used / usage.total) * 100
                }
            except Exception as e:
                logger.error(f"读取主机磁盘信息失败: {e}")
        
        # 如果没有主机挂载，回退到本地磁盘信息
        if not disk_usage:
            disk_usage = self._get_local_disk_info()
            
        return disk_usage
    
    def _get_local_disk_info(self) -> Dict:
        """获取本地磁盘信息"""
        disk_usage = {}
        for partition in psutil.disk_partitions():
            try:
                partition_usage = psutil.disk_usage(partition.mountpoint)
                disk_usage[partition.mountpoint] = {
                    'total': partition_usage.total,
                    'used': partition_usage.used,
                    'free': partition_usage.free,
                    'percent': (partition_usage.used / partition_usage.total) * 100
                }
            except PermissionError:
                continue
        return disk_usage
    
    def get_host_network_info(self) -> Dict:
        """获取主机网络信息"""
        # 网络信息在容器中通常是隔离的，这里返回容器的网络信息
        # 如果需要主机网络信息，需要更复杂的实现
        try:
            network = psutil.net_io_counters()
            return {
                'bytes_sent': network.bytes_sent,
                'bytes_recv': network.bytes_recv,
                'packets_sent': network.packets_sent,
                'packets_recv': network.packets_recv
            }
        except:
            return {
                'bytes_sent': 0,
                'bytes_recv': 0,
                'packets_sent': 0,
                'packets_recv': 0
            }
    
    def get_comprehensive_status(self) -> Dict:
        """获取综合的主机状态信息"""
        return {
            'cpu': self.get_host_cpu_info(),
            'memory': self.get_host_memory_info(),
            'disk': self.get_host_disk_info(),
            'network': self.get_host_network_info(),
            'environment': {
                'is_container': self.is_in_container,
                'host_proc_path': self.host_proc_path if self.is_in_container else None,
                'host_sys_path': self.host_sys_path if self.is_in_container else None
            }
        }